#include "mesh.h"

//Array in which the mesh textures are stored
GLuint mesh_image[4];

//The width of the mesh
const int WIDTH = 256.00;

//Number of triangles
int num_tri = ((WIDTH-1)*(WIDTH-1));

//Number of vertices
int num_vertices = WIDTH * WIDTH;

//This array is used to store the height data which the vertexList array will use
GLfloat height[WIDTH*WIDTH];

//This array is used to store the indices for this mesh.
GLuint tri_indexList[(WIDTH-1)*(WIDTH-1)*6];

//This array is used to store the vertices for this mesh
GLfloat vertexList[WIDTH*WIDTH][3];

//This array is used to store colour data at each vertrex
GLfloat normalList[WIDTH*WIDTH*3][3];

//This array is used to store the s and t coordinates of the texture
GLfloat texList[WIDTH*WIDTH][2];

/////ODE
////dHeightfieldDataID dGeomHeightfieldDataCreate ();
//void dGeomHeightfieldDataDestroy (dHeightfieldDataID d)



//This function will normalize the values obtained from applying the cross product
void mesh::normalize(float v[])
{
	float n1 = v[0]*v[0];
	float n2 = v[1]*v[1];
	float n3 = v[2]*v[2];
	float nt= n1+n2+n3;
		GLfloat d = sqrt(nt);

		if ( d==0.0) {
			//cout << "zero length vector";
			return;
		}

		v[0] /= d;
		v[1] /= d;
		v[2] /= d;
}

//This function will find the cross product and send the results to normalize()
void mesh::normcrossprod(float v1[3], float v2[3], float out[3])
{
		out[0] = v1[1]*v2[2] - v1[2]*v2[1];
		out[1] = v1[2]*v2[0] - v1[0]*v2[2];
		out[2] = v1[0]*v2[1] - v1[1]*v2[0];
		normalize(out);
}
void mesh::init(const char * bitmap_file, CTexture* texMesh)
{
	m_texMesh = texMesh;
	glbmp_t bitmap;

	if(!glbmp_LoadBitmap(bitmap_file, 0, &bitmap))
 	{
		fprintf(stderr, "Error loading bitmap file: %s\n", bitmap_file);
		exit(1);
	}

	unsigned char *bit;
	bit = bitmap.rgb_data;

	//This will loop through each time until the size of the array is equal to the size
	//of the heightmap image
	for(int index =0; index< bitmap.width*bitmap.width; index++)
	{
		height[index] = 10-(((float) *bit)/5);	//bit is declared as float so it will be able to 
												//store decimal values (if it is not changed to float
												//then the heighmap starts to look blocky when there is
												// a change in elevation)
		bit+=3;
	}

	glbmp_FreeBitmap(&bitmap);

	//height_ID, Indice_ID and normal_ID are used to define the exact location in the height,
	//indexList and normalList array.
	int height_ID = 0;
	int indice_ID = 0;
	int normal_ID = 0;
	
	//These arrays will be used when calculating the normals for each vector.
	GLfloat d1[3], d2[3], norm[3];
	
	//This is used to define what scale the texture should be mapped at each vertice
	double textureMap_scale = 1.00/(WIDTH-1.00);

	//This nested loop will generate and store values for the vertexList, 
	//colorList and texture List array
	for(int z=0; z<=(WIDTH-1); z++)
	for(int x=0; x<=(WIDTH-1); x++)
	{
		//This will generate data into the 2d array which will be used when
		//plotting the s and t values of the chosen texture
		texList[z * WIDTH + x][0] = x * textureMap_scale;	
		texList[z * WIDTH + x][1] = z * textureMap_scale;
		
		//This will generate data into the 3d array which will be used to
		//plot x,z, and height of each vertex
		vertexList[z * WIDTH + x][0] = x;
		vertexList[z * WIDTH + x][1] = height[height_ID++];
		vertexList[z * WIDTH + x][2] = z;

 		
		//Code to grab a texture from a bitmap with multiple images depending on the height of the mesh
		//at each point.(not working need to play about with the values and use GL_REPEAT to prevent
		//getting stretched textures)
	 //int s = textureMap_scale;
	 //int t = textureMap_scale*4;
		//if ((vertexList[z * WIDTH + x][1] > 0.0f))
		//	{s = (textureMap_scale*4);
		//	 t = (textureMap_scale*4);}
		////else if((vertexList[z * WIDTH + x][1] >= 0.1f) && (vertexList[z * WIDTH + x][1] <= 0.6f))
		//{s = (textureMap_scale*4);
		//t= (textureMap_scale*4);}
		//else if(vertexList[z * WIDTH + x][1] >0.7f)
		//{s=(textureMap_scale*4);
		//t=0;}
		//texList[z * WIDTH + x][0] = (((x * (textureMap_scale)/2)) + s);	
		//texList[z * WIDTH + x][1] = (((z * (textureMap_scale)/2)) + t);
	}

	//This nested loop will generate the values for each indice and store them in
	//the tri_indexList array
	for (int z = 0; z < ((WIDTH-1) * (WIDTH-1)); z += (WIDTH))
	for (int x = 0; x < (WIDTH-1); x++)
	{
		//Frist Triangle (e.g. 0, 1, 20)
		tri_indexList[indice_ID+0] = (x) + z;
		tri_indexList[indice_ID+1] = (x + 1) + z;
		tri_indexList[indice_ID+2] = (x + (WIDTH)) + z;
		indice_ID+=3;
		
		//Second Triangle (e.g. 1, 21, 20)
		tri_indexList[indice_ID+0] = (x + 1) + z;
		tri_indexList[indice_ID+1] = (x + (WIDTH + 1)) + z;
		tri_indexList[indice_ID+2] = (x + (WIDTH)) + z;
		indice_ID+=3;
	}
	
	//This nested loop will generate vlaues for normals and store them in
	//the normalList array.
	for( int i = 0; i < num_tri*6 ; i+= 3 ){
	for ( int j = 0; j< 3; j++)
	{
		d1[j] = vertexList[tri_indexList[i+0]][j] - vertexList[tri_indexList[i+1]][j];
		d2[j] = vertexList[tri_indexList[i+1]][j] - vertexList[tri_indexList[i+2]][j];
	}
	normcrossprod(d1, d2, norm);
	normalList[normal_ID][0]= norm[0];
	normalList[normal_ID][1]= norm[1];
	normalList[normal_ID][2]= norm[2];
	normal_ID++;
	}


	////ODE
	//void dGeomHeightfieldDataBuildByte   (dHeightfieldDataID d,
 //                                     const unsigned char *pHeightData,
 //                                     int bCopyHeightData,
 //                                     dReal width, dReal depth,
 //                                     int widthSamples, int depthSamples,
 //                                     dReal scale, dReal offset, dReal thickness, int bWrap);
 //
	//void dGeomHeightfieldDataBuildShort  (dHeightfieldDataID d,
 //                                     const short *pHeightData,
 //                                     int bCopyHeightData,
 //                                     dReal width, dReal depth,
 //                                     int widthSamples, int depthSamples,
 //                                     dReal scale, dReal offset, dReal thickness, int bWrap);
 //
	//void dGeomHeightfieldDataBuildSingle (dHeightfieldDataID d,
 //                                     const float *pHeightData,
 //                                     int bCopyHeightData,
 //                                     dReal width, dReal depth,
 //                                     int widthSamples, int depthSamples,
 //                                     dReal scale, dReal offset, dReal thickness, int bWrap);
 //
	//void dGeomHeightfieldDataBuildDouble (dHeightfieldDataID d,
 //                                     const double *pHeightData,
 //                                     int bCopyHeightData,
 //                                     dReal width, dReal depth,
 //                                     int widthSamples, int depthSamples,
 //                                     dReal scale, dReal offset, dReal thickness, int bWrap);


}
void mesh::draw()
{
	
	//glLoadIdentity();
	glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST);
    glEnable(GL_TEXTURE_2D);
	//glEnable(GL_LIGHTING);
	glDisable(GL_LIGHTING);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE); //culling is enabled so the md2 model does not become hidden by the mesh
	glCullFace(GL_FRONT);	//at various camera angles
	
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	//glBindTexture(GL_TEXTURE_2D, mesh_image[2]);
	m_texMesh->BindTexture ( );
	glColor3f(1.0f, 1.0f, 1.0f);
	glTranslatef(-128.0f, 0.0f, -128.0f);

	glPushMatrix();
		glDrawElements(GL_TRIANGLES,num_tri*6,GL_UNSIGNED_INT,tri_indexList);
	glPopMatrix();
	
	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	glDisable(GL_TEXTURE_2D);
	
}

void mesh::main()
{
	//calls the vertex, texture and normal data so it can be used
	//glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState( GL_TEXTURE_COORD_ARRAY );
	glNormalPointer(GL_FLOAT,0,normalList);
	glVertexPointer(3,GL_FLOAT,0,vertexList);
	glTexCoordPointer(2, GL_FLOAT, 0, texList);
}

